﻿using System;
using System.Collections.Generic;
using NJabber.Client.StanzaFactories;
using NJabber.Stream;
using NJabber.Stream.Elements;

namespace NJabber.Client
{
    public abstract class XmppClientRuntime
    {
        public abstract IRosterCache RosterCache { get; }

        public abstract IRosterStanzaFactory RosterStanzaFactory { get; }
        public abstract IPresenceStanzaFactory PresenceStanzaFactory { get; }
        public abstract IMessageStanzaFactory MessageStanzaFactory { get; }
        public abstract ISubscriptionStanzaFactory SubscriptionStanzaFactory { get; }

        public abstract IPresenceStatusProvider PresenceStatusProvider { get; }
        public abstract IPresenceStatusUpdater PresenceStatusUpdater { get; }
        public abstract IPresenceSubscriptionRegistry SubscriptionRegistry { get; }

        public abstract IXmppConnection Connection { get; }

        public JID ClientJid
        {
            get
            {
                if (Connection != null) return Connection.Jid;
                return null;
            }
        }

        public IStanzaStream StanzaStream
        {
            get
            {
                if (Connection != null) return Connection.Stream;
                return null;
            }
        }

        public abstract IEnumerable<IStanzaHandler> StanzaHandlers { get; } 
    }

    public class StandartClientRuntime : XmppClientRuntime
    {
        private IServiceProvider serviceProvider;

        private Lazy<IRosterCache> rosterCache;
        private Lazy<IMessageStanzaFactory> messageStanzaFactory;
        private Lazy<IPresenceStanzaFactory> presenceStanzaFactory;
        private Lazy<IRosterStanzaFactory> rosterStanzaFactory;
        private Lazy<ISubscriptionStanzaFactory> subscriptionStanzaFactory;
        private Lazy<IPresenceStatusProvider> presenceStatusProvider;
        private Lazy<IPresenceStatusUpdater> presenceStatusUpdater;
        private Lazy<IXmppConnection> connection;
        private Lazy<IPresenceSubscriptionRegistry> presenceSubscriptionRegistry; 
        private Lazy<IEnumerable<IStanzaHandler>> stanzaHandlers;

        public StandartClientRuntime(IServiceProvider serviceProvider)
        {
            if (serviceProvider == null) throw new ArgumentNullException("serviceProvider");

            this.serviceProvider = serviceProvider;
            rosterCache = GetLazyService<IRosterCache>();
            messageStanzaFactory = GetLazyService<IMessageStanzaFactory>();
            presenceStanzaFactory = GetLazyService<IPresenceStanzaFactory>();
            rosterStanzaFactory = GetLazyService<IRosterStanzaFactory>();
            subscriptionStanzaFactory = GetLazyService<ISubscriptionStanzaFactory>();
            presenceStatusProvider = GetLazyService<IPresenceStatusProvider>();
            presenceStatusUpdater = GetLazyService<IPresenceStatusUpdater>();
            connection = GetLazyService<IXmppConnection>();
            presenceSubscriptionRegistry = GetLazyService<IPresenceSubscriptionRegistry>();
            stanzaHandlers = GetLazyService<IEnumerable<IStanzaHandler>>();
        }

        private Lazy<T> GetLazyService<T>()
        {
            return new Lazy<T>(GetService<T>);
        }

        private T GetService<T>()
        {
            return (T)serviceProvider.GetService(typeof(T));
        }

        public override IRosterCache RosterCache 
        { 
            get { return rosterCache.Value; } 
        }

        public override IMessageStanzaFactory MessageStanzaFactory 
        { 
            get { return messageStanzaFactory.Value; } 
        }

        public override IPresenceStanzaFactory PresenceStanzaFactory
        {
            get { return presenceStanzaFactory.Value; }
        }

        public override IRosterStanzaFactory RosterStanzaFactory 
        { 
            get { return rosterStanzaFactory.Value; } 
        }

        public override ISubscriptionStanzaFactory SubscriptionStanzaFactory 
        {
            get { return subscriptionStanzaFactory.Value; }
        }

        public override IPresenceStatusProvider PresenceStatusProvider 
        {
            get { return presenceStatusProvider.Value; }
        }

        public override IPresenceStatusUpdater PresenceStatusUpdater 
        {
            get { return presenceStatusUpdater.Value; }
        }
        public override IPresenceSubscriptionRegistry SubscriptionRegistry
        {
            get { return presenceSubscriptionRegistry.Value; }
        }

        public override IXmppConnection Connection 
        {
            get { return connection.Value; }
        }

        public override IEnumerable<IStanzaHandler> StanzaHandlers
        {
            get { return stanzaHandlers.Value; }
        }

        public IEventMediator Event { get; set; }
    }

    public interface IEventMediator
    {
        void OnMessageStanza(MessageStanza stanza);
    }

    public interface IXmppConnection
    {
        ConnectionState State { get; }
        IStanzaStream Stream { get; }
        JID Jid { get; }
        void Open();
        void Close();
        event EventHandler Opened;
        event EventHandler Closed;
    }

    public enum ConnectionState
    {
        Opened,
        Closed
    }

    public class XmppConnection : IXmppConnection
    {

        public ConnectionState State
        {
            get { throw new NotImplementedException(); }
        }

        public IStanzaStream Stream
        {
            get { throw new NotImplementedException(); }
        }

        public JID Jid
        {
            get { throw new NotImplementedException(); }
        }

        public void Open()
        {
            throw new NotImplementedException();
        }

        public void Close()
        {
            throw new NotImplementedException();
        }

        public event EventHandler Opened;

        public event EventHandler Closed;
    }
}
